/**
 * 用户页面停留时长
 */
import { ReportType } from './constant';
import { ReportParams } from './types';
import Utils from './utils';

export default class PageDwellTime {
	// 配置常量
	OFFLINE_MILL = 15 * 60 * 1000; // 15分钟不操作认为不在线
	MIN_DURATION = 1000; // 最小有效停留时间(1秒)

	// 状态变量
	lastTime: number;
	lastActiveTime: number; // 最后活动时间
	prePageUrl: string;

	constructor(private callback: (params: ReportParams) => void) {
		Utils.log('用户页面停留时长初始化成功');

		this.prePageUrl = encodeURIComponent(location.href);
		const time = performance.now();
		this.lastTime = time;
		this.lastActiveTime = time;
		this.init();
	}

	init() {
		setTimeout(() => {
			// 路由变化监听
			Utils.routerChangeListener(() => {
				this.reportDwellTime();
				this.prePageUrl = encodeURIComponent(location.href);
			});
		}, 100);

		// 用户活动监听（防止误判离线）
		window.addEventListener('mousemove', this.updateLastActiveTime.bind(this));
		window.addEventListener('keydown', this.updateLastActiveTime.bind(this));

		// 页面关闭监听
		window.addEventListener('beforeunload', this.handlePageUnload.bind(this));
		window.addEventListener('pagehide', this.handlePageUnload.bind(this));

		// 重置
		window.addEventListener('pageshow', () => {
			this.lastTime = performance.now();
			this.lastActiveTime = performance.now();
		});
	}

	/**
	 * 更新最后活动时间
	 */
	private updateLastActiveTime(): void {
		this.lastActiveTime = performance.now();
	}

	/**
	 * 处理页面卸载
	 */
	private handlePageUnload(): void {
		// 上报停留时间
		this.reportDwellTime();
	}

	/**
	 * 上报停留时间
	 */
	private reportDwellTime(): void {
		const now = performance.now();
		const duration = now - this.lastTime;
		const activeTime = now - this.lastActiveTime;
		// 忽略过短的停留时间
		if (duration < this.MIN_DURATION) {
			Utils.log('debug', `忽略过短的停留时间: ${Math.round(duration)}ms`);
			return;
		}

		// 超过十五分钟，判定为掉线
		if (activeTime > this.OFFLINE_MILL) {
			Utils.log('debug', `检测到离线状态: ${Math.round(duration / 1000)}秒`);
			this.lastTime = now;
			this.lastActiveTime = now;
			return;
		}

		// 准备上报数据
		const reportData: ReportParams = {
			type: ReportType.PAGE_DWELL_TIME,
			message: '页面停留时长',
			duration: Math.round(duration), // ms
			pageUrl: this.prePageUrl,
			visibilityState: document.visibilityState,
		};
		this.callback(reportData);
		Utils.log('debug', `页面停留上报: ${Math.round(duration)}ms`);
		// 更新时间戳
		this.lastTime = now;
		this.lastActiveTime = now;
	}
}
